//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <winhack.h>
#include <elasys_server.h>
#include <string.h>
#include <elapi.h>
#include <stdlib.h>
#include <netcard.h>
#include <stdio.h>
#include <msgqueue.h>
#include <sysconfig.h>
#include <driver.h>

#include "ethermain.h"

// MAC address declared in etherimp.cpp
extern unsigned char    cMacAddr[6];
extern wchar_t          wEtherID[100];

EXTERN_C BOOL EtherInit();
EXTERN_C void EtherSendPacket(char *buf, unsigned io_len);
EXTERN_C void EtherReceivePacket();

extern Node g_nodereadlist;

ECode NetCard::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 uNumberOfBytesToRead,
    /* [out] */ BufferOf<Byte> * pData,
    /* [out] */ IEvent * * ppCompletionEvent)
{
   // printf("+NetCard::Read\n");

    // Not empty, return, else read until not empty

    while (g_nodereadlist.IsEmpty()) {
        EtherReceivePacket();
    }

    Node * pnode = g_nodereadlist.GetNode();

    if (pData == NULL) {
        return E_INVALID_ARGUMENT;
    }
    pData->Copy((Byte *)pnode->m_address, pnode->m_len);
    delete pnode;

    //printf("-NetCard::Read\n");
    return NOERROR;
}

ECode NetCard::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const BufferOf<Byte> & ebbData,
    /* [out] */ Int32 * puNumberOfBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    //printf("+NetCard::Write. size: %d\n", ebbData.GetUsed());

    char * pBuf = (char *)ebbData.GetPayload();

    // send the packet
    EtherSendPacket(pBuf, ebbData.GetUsed());

    //printf("-NetCard::Write\n");
    return NOERROR;
}

ECode NetCard::Control(
    /* [in] */ Int32 nControlCode,
    /* [in] */ const BufferOf<Byte> & ebbInData,
    /* [out] */ BufferOf<Byte> * pOutData,
    /* [out] */ IEvent ** ppCompletionEvent)
{
    // printf("NetCard::Control,  code is %d\n", nControlCode);

    if (nControlCode == DRVINITALIZE) {
        // Init virtual network driver
        if (!EtherInit()) {
            wprintf(L"NetCard::Control: At file %d, line %d.\n", __FILE__, __LINE__);
            return E_INVALID_OPERATION;
        }

        printf("Return Mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
            cMacAddr[0],cMacAddr[1],cMacAddr[2],
            cMacAddr[3],cMacAddr[4],cMacAddr[5]);

        // return the MAC address
        if (pOutData == NULL) {
            return E_INVALID_ARGUMENT;
        }
        pOutData->Copy(cMacAddr, 6);
    }
    else if (nControlCode == DRVSHUTDOWN) {
        ;
    }
    else {
        printf("unknown ControlCode %d\n", nControlCode);
    }
    return NOERROR;
}

void NetCard::Dispose()
{
    //delete this;
}

IDeviceDriver *pDriver;//use for wrap_sharp.cpp
extern int usnetEntry();

EXTERN IDeviceDriver * CDECL CreateNetCard(uint_t uDeviceNo, void *pvParameter)
{
    pDriver = new NetCard();
    if (NULL == pDriver) {
        return NULL;
    }
    pDriver->AddRef();

    // Get Ethernet Card ID and Mac Address
    ECode ec = _CProfile_GetWString(L"Tcpip", L"EtherCardID", (WChar *)wEtherID, 100);

    if (FAILED(ec)) {
        printf("Failed to Read Ethernet Configuration.\n");
        return NULL;
    }

    wprintf(L"Use Ethernet Card %s\n", wEtherID);

    // Generate Mac Address randomly.
    SystemTime tm;
    _CSystem_GetMachineTime(&tm);

    srand(tm.seconds + tm.microseconds);

    int i = 0;
    for (; i < 6; i++) {
        cMacAddr[i] = rand() % 255;
    }

    usnetEntry();

    return pDriver;
}
